package run.siyuan.jdk.新特性;

import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author siyuan
 * @description: TODO Stream 相关操作
 * @date 2021/4/30 10:13 上午
 */
public class StreamTest {

    /**
     * 流的创建方式
     */
    @Test
    public void test1() {
        // Stream 流的种类：顺序流、并行流
//        List<String> list = Arrays.asList("a", "b", "c");
        // 创建一个顺序流
//        Stream<String> stream = list.stream();
        // 创建一个并行流
//        Stream<String> parallelStream = list.parallelStream();

//        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);

        Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
        stream2.forEach(System.out::println);

        Stream<Double> stream3 = Stream.generate(Math::random).limit(3);
        stream3.forEach(System.out::println);
    }

    /**
     * 遍历/匹配（foreach/find/match）
     */
    @Test
    public void test2() {

        // Stream 循环遍历
        List<Integer> list = Arrays.asList(1, 5, 6, 2, 5, 4, 8, 9, 7, 3);
        list.stream().forEach(System.out::println);
        List<Integer> collect = list.stream().filter(item -> item.equals(5)).collect(Collectors.toList());
        System.out.println("5 的个数"+collect);

        // 获取匹配到的第一个值
        Optional<Integer> first = list.stream().filter(item -> item.equals(5)).findFirst();
        System.out.println("first:" + first.toString());
        System.out.println("first valut:" + first.get());

        // 获取匹配到的任意一个值（顺序流）
        Optional<Integer> any = list.stream().filter(item -> item.equals(5)).findAny();
        System.out.println("any:" + any.toString());
        System.out.println("any value:" + any.get());

        // 获取匹配到的任意一个值（并行流）
        any = list.parallelStream().filter(item -> item.equals(5)).findAny();
        System.out.println("any:" + any.toString());
        System.out.println("any value:" + any.get());

        // 所有元素小于10 true
        boolean result = list.stream().allMatch(item -> item < 10);
        System.out.println("item < 10 " + result);
        // 存在元素等于1 true
        result = list.stream().anyMatch(item -> item.equals(1));
        System.out.println("顺序流 item == 1 " + result);
        // 存在元素等于1 true
        result = list.parallelStream().anyMatch(item -> item.equals(1));
        System.out.println("并行流 item == 1 " + result);
        // 没有元素小于10 true
        result = list.stream().noneMatch(item -> item < 10);
        System.out.println("item < 10 " + result);

    }

    /**
     * 筛选（filter）
     */
    @Test
    public void test3() {
        List<Person> personList = getPersonList();
        // 所有员工工资大于 8000 的员工
        List<Person> collect = personList.stream().filter(item -> item.getSalary() > 8000).collect(Collectors.toList());
        System.out.println("所有员工工资大于 8000 的员工：" + collect.toString());

        // 所有员工工资大于 8000 的员工工资
        List<Integer> salaryList = personList.stream().filter(item -> item.getSalary() > 8000).map(Person::getSalary).collect(Collectors.toList());
        System.out.println("所有员工工资大于 8000 的员工工资：" + salaryList.toString());


        personList.addAll(getPersonList());
        System.out.println(personList + " : " + personList.size());

        // 过滤list集合特性属性相同的元素
        ArrayList<Person> list = personList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(
                () -> new TreeSet<>(Comparator.comparing(item -> item.getName() + item.getSalary()))
        ), ArrayList::new));
        System.out.println(list + " : " + list.size());
    }

    /**
     * 聚合（max/min/count)
     */
    @Test
    public void test4() {
        // 查找字符串长度最大
        List<String> list = Arrays.asList("adnm", "admmt", "pot", "xbangd", "weoujgsd");
        Optional<String> maxStr = list.stream().max(Comparator.comparing(String::length));
        System.out.println("maxStr:" + maxStr);
        System.out.println("maxStr value:" + maxStr.get());

        // 查找字符串长度最小
        Optional<String> minStr = list.stream().min(Comparator.comparing(String::length));
        System.out.println("minStr:" + minStr);
        System.out.println("minStr value:" + minStr.get());

        // 查找最大值
        List<Integer> integers = Arrays.asList(7, 6, 9, 4, 11, 6);
        Optional<Integer> maxInt = integers.stream().max(Comparator.comparingInt(Integer::intValue));
        System.out.println("maxInt:" + maxInt);
        System.out.println("maxInt value：" + maxInt.get());

        // 查找最小值
        Optional<Integer> minInt = integers.stream().min(Integer::compareTo);
        System.out.println("minInt:" + minInt);
        System.out.println("minInt valut:" + minInt.get());

        // 查询工资最高的员工
        List<Person> personList = getPersonList();
        Optional<Person> maxPerson = personList.stream().max(Comparator.comparingInt(Person::getSalary));
        System.out.println("maxPerson:" + maxPerson);
        System.out.println("maxPerson valut:" + maxPerson.get());

        // 查询工资最低的员工
        Optional<Person> minPerson = personList.stream().min(Comparator.comparingInt(Person::getSalary));
        System.out.println("minPerson:" + minPerson);
        System.out.println("minPerson value:" + minPerson.get());

        // 员工工资大于 8000 员工数
        long count = personList.stream().filter(item -> item.getSalary() > 8000).count();
        System.out.println("员工工资大于 8000 员工数：" + count);

        // 将员工工资增加 1000
        // 1、不改变原员工数据
        List<Person> newPersonList = personList.stream().map(item -> {
            return new Person(item.getName(), item.getSalary() + 1000, item.getAge(), item.getSex(), item.getArea());
        }).collect(Collectors.toList());
        System.out.println("newPersonList:" + newPersonList);
        System.out.println("personList:" + personList);
        // 2、改变原来数据
        personList.stream().map(item -> {
            item.setSalary(item.getSalary() + 1000);
            return item;
        }).collect(Collectors.toList());
        System.out.println("personList:" + personList);

        // 将两个字符串合并成一个集合
        List<String> strList = Arrays.asList("m-k-l-a", "1-3-5-7");
        List<String> newStrList = strList.stream().flatMap(item -> {
            String[] split = item.split("-");
            return Arrays.stream(split);
        }).collect(Collectors.toList());
        System.out.println("newStrList:" + newStrList);

    }

    /**
     * 归约，也称缩减，顾名思义，是把一个流缩减成一个值，能实现对集合求和、求乘积和求最值操作。
     */
    @Test
    public void test5() {
        // 求和
        List<Integer> list = Arrays.asList(1, 3, 2, 8, 11, 4);
        Optional<Integer> sumOptional = list.stream().reduce((x, y) -> x + y);
        System.out.println("sum:" + sumOptional.get());
        sumOptional = list.stream().reduce(Integer::sum);
        System.out.println("sum:" + sumOptional.get());
        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println("sum:" + sum);

        // 求积
        Optional<Integer> produceOptional = list.stream().reduce((x, y) -> x * y);
        System.out.println("product:" + produceOptional.get());

        // 最大值
        Optional<Integer> maxOPtional = list.stream().reduce(Integer::max);
        System.out.println("maxOptional:" + maxOPtional.get());
        List<Person> personList = getPersonList();


        // 最大值
        Optional<Integer> reduce = personList.stream().map(Person::getSalary).reduce(Integer::max);
        System.out.println("reduce:" + reduce.get());
        Integer max = personList.stream().reduce(0, (pMax, p) -> pMax > p.getSalary() ? pMax : p.getSalary(), Integer::max);
        System.out.println("员工工资大为：" + max);
        // 求和
        Optional<Integer> optional = personList.stream().map(Person::getSalary).reduce(Integer::sum);
        System.out.println("optional:" + optional.get());
        sum = personList.stream().reduce(0, (pSum, p) -> pSum += p.getSalary(), (sum1, sum2) -> sum1 + sum2);
        System.out.println("员工工资之和：" + sum);
        sum = personList.stream().reduce(0, (pSum, p) -> pSum += p.getSalary(), (Integer::sum));
        System.out.println("员工工资之和：" + sum);

    }


    /**
     * 收集
     */
    @Test
    public void test6() {
        List<Integer> integerList = Arrays.asList(1, 6, 3, 4, 6, 7, 9, 6, 20);
        List<Integer> collect = integerList.stream().filter(item -> item > 2).collect(Collectors.toList());
        System.out.println("collect:" + collect);
        Set<Integer> set = integerList.stream().filter(item -> item % 2 == 1).collect(Collectors.toSet());
        System.out.println("set:" + set);

        set = integerList.stream().filter(item -> item == 10).collect(Collectors.toSet());
        System.out.println("filter 10 set:" + set);

        List<Person> personList = getPersonList();
        Map<String, Person> map = personList.stream().filter(item -> item.getSalary() > 8000).collect(Collectors.toMap(Person::getName, p -> p));
        System.out.println("map:" + map);

        Map<String, Person> collect1 = personList.stream().collect(Collectors.toMap(item -> item.getName() + item.getSalary(), p -> p));
        System.out.println(collect1);
    }

    /**
     * 统计
     */
    @Test
    public void test7() {
        List<Person> personList = getPersonList();
        Long count = personList.stream().collect(Collectors.counting());
        System.out.println("count：" + count);
        Double avag = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
        System.out.println("avag：" + avag);
        Optional<Integer> optional = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compareTo));
        System.out.println("max：" + optional.get());
        Integer integer = personList.stream().collect(Collectors.summingInt(Person::getSalary));
        System.out.println("sum:" + integer);
        DoubleSummaryStatistics doubleSummaryStatistics = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
        System.out.println("summarizingDouble:" + doubleSummaryStatistics);
    }

    /**
     * 分组
     */
    @Test
    public void test8() {
        List<Person> personList = getPersonList();
        Map<Boolean, List<Person>> part = personList.stream().collect(Collectors.partitioningBy(item -> item.getSalary() > 8000));
        System.out.println("将员工按薪资是否高于8000分组:" + part);
        Map<String, List<Person>> group = personList.stream().collect(Collectors.groupingBy(Person::getSex));
        System.out.println("将员工按性别分组:" + group);
        personList.addAll(getPersonList());
        Map<String, List<Person>> collect = personList.stream().collect(Collectors.groupingBy(Person::getName));
        System.out.println("按照姓名分组:"+collect);
        Map<String, Map<String, List<Person>>> group2 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getArea)));
        System.out.println("将员工先按性别分组，再按地区分组:" + group2);

    }

    /**
     * 结合
     */
    @Test
    public void test9(){
        List<Person> personList = getPersonList();
        String collect = personList.stream().map(item -> item.getName()).collect(Collectors.joining(","));
        System.out.println("所有员工姓名："+collect);

        List<String> list = Arrays.asList("A", "B", "C");
        String strs = list.stream().collect(Collectors.joining("-"));
        System.out.println("strs:"+strs);
    }

    @Test
    public void test10(){
        List<Person> personList = getPersonList();
        System.out.println(personList);
        personList.stream().forEach(item -> item.setSalary(item.getSalary() + 1000));
        System.out.println(personList);
    }

    @Test
    public void test11(){
        List<Person> personList = getPersonList();
        Map<String, Person> collect = personList.stream().collect(Collectors.toMap(Person::getName, person -> person));
        System.out.println(collect);
        System.out.println(collect.size());

        personList.addAll(getPersonList());
        System.out.println(personList.size());
        collect = personList.stream().collect(Collectors.toMap(Person::getName, Function.identity(), (person,person2) -> person));
        System.out.println(collect);
        System.out.println(collect.size());
    }

    @Test
    public void test12(){
        List<Person> personList = getPersonList();
        personList = personList.stream().filter(person -> person.getAge() == 25).collect(Collectors.toList());
        System.out.println(personList);
    }

    /**
     * 获取 Person 集合
     *
     * @return
     */
    public List<Person> getPersonList() {
        List<Person> personList = new ArrayList<>(7);
        personList.add(new Person("Tom", 8900, 23, "male", "New York"));
        personList.add(new Person("Jack", 7000, 25, "male", "Washington"));
        personList.add(new Person("Lily", 7800, 21, "female", "Washington"));
        personList.add(new Person("Anni", 8200, 24, "female", "New York"));
        personList.add(new Person("Owen", 9500, 25, "male", "New York"));
        personList.add(new Person("Alisa", 7900, 26, "female", "New York"));
        return personList;
    }


    class Person {
        private String name;  // 姓名
        private int salary; // 薪资
        private int age; // 年龄
        private String sex; //性别
        private String area;  // 地区

        // 构造方法
        public Person(String name, int salary, int age, String sex, String area) {
            this.name = name;
            this.salary = salary;
            this.age = age;
            this.sex = sex;
            this.area = area;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getSalary() {
            return salary;
        }

        public void setSalary(int salary) {
            this.salary = salary;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public String getSex() {
            return sex;
        }

        public void setSex(String sex) {
            this.sex = sex;
        }

        public String getArea() {
            return area;
        }

        public void setArea(String area) {
            this.area = area;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", salary=" + salary +
                    ", age=" + age +
                    ", sex='" + sex + '\'' +
                    ", area='" + area + '\'' +
                    '}';
        }
    }

}
